home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Sample Code / AOCE Sample Code / PowerTalk Access Modules / Sample PMSAM / PMSAM Framework / RoboSamSlot / TThread.cp < prev    next >
Encoding:
Text File  |  1995-07-28  |  11.4 KB  |  489 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        TThread.cp
  3.  
  4.     Contains:    xxx put contents here xxx
  5.  
  6.     Written by:    Tim Harnett
  7.  
  8.     Copyright:    © 1994 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.         <13>      2/7/95    TMH        added userinterrupt stuff
  13.         <12>      2/6/95    TMH        redid CEventQueue using CLinkedList
  14.         <11>    12/20/94    TMH        fix bug so we don't overflow event queue
  15.         <10>    12/12/94    TMH        added of thread events
  16.          <9>    11/17/94    TMH        fix to TWakeupThread::Busy
  17.          <8>    11/11/94    TMH        fixed TWakeupThread::Busy() to look at IO state
  18.          <7>    11/10/94    TMH        use StopForIO
  19.          <6>     11/8/94    TMH        added fIdentifierTag
  20.          <5>    10/28/94    TMH        added gAppTaskRef and StartThreadFromCompletionRoutine
  21.          <4>    10/26/94    TMH        added GetThreadA5
  22.          <3>    10/25/94    TMH        added TWakeupThread
  23.          <2>     10/6/94    TMH        added TApplicationThread
  24.          <1>     9/21/94    TMH        seperated from Application.cp
  25.                  9/21/94    TMH        xxx put comment here xxx
  26.  
  27.     To Do:
  28. */
  29.  
  30. #ifndef __STRING__
  31. #include <String.h>
  32. #endif
  33.  
  34. #ifndef __TYPES__
  35. #include <Types.h>
  36. #endif
  37.  
  38. #ifndef __Debug__
  39. #include "Debug.h"
  40. #endif
  41.  
  42. #ifndef __UFAILURE__
  43. #include "UFailure.h"
  44. #endif
  45.  
  46. #ifndef __Globals__
  47. #include "Globals.h"
  48. #endif
  49.  
  50. #ifndef __TThread__
  51. #include "TThread.h"
  52. #endif
  53.  
  54. #ifndef __Application__
  55. #include "Application.h"
  56. #endif
  57.  
  58.  
  59.  
  60.     ThreadTaskRef TCooperativeThread::gAppTaskRef = 0;
  61.     unsigned long    TCooperativeThread::gDebugCallCount = 0;        // this is for debugging, remove it later
  62. #pragma segment TThread
  63.  
  64. //-----------------------------------------------
  65. //        T C o o p e r a t i v e T h r e a d
  66. //-----------------------------------------------
  67.  
  68.  
  69. //-------------------------------------------------------------------------------------
  70. TCooperativeThread::TCooperativeThread()
  71. {
  72.     fThreadID = 0;
  73.     fOutParam = 0;
  74.     fWNESleep = kSleepTime;
  75.     
  76.     fSavedTopHandler = 0;
  77.     fA5 = ::SetCurrentA5();
  78.     
  79.     fIdentifierTag = 0;
  80.     
  81.     fThreadIOState = sThreadIOIdle;
  82.     
  83.     
  84.     fEventQueue = 0;
  85.     
  86.     fUserInterrupt = 0;
  87. }
  88.  
  89.  
  90.  
  91. //-------------------------------------------------------------------------------------
  92. TCooperativeThread::~TCooperativeThread()
  93. {
  94.     if( fEventQueue != 0 )
  95.         DisposePtr((Ptr)fEventQueue);
  96.         
  97.     ASSERT(this->GetThreadState() == kStoppedThreadState );
  98.     ASSERT(fThreadID != 0 );
  99.     
  100.     OSErr osErr = DisposeThread(fThreadID,0,false);
  101.     ASSERTNOERR(osErr);
  102.     
  103. }
  104.  
  105.  
  106. //-------------------------------------------------------------------------------------
  107. void TCooperativeThread::ICooperativeThread(OSType tag, Size stackSize,ThreadOptions createOptions,long wneSleep)
  108. {
  109.         // filter out our extensions
  110.     ThreadOptions    threadMgrOptions = createOptions & (kNewSuspend+kUsePremadeThread+kCreateIfNeeded+kFPUNotNeeded+kExactMatchThread);
  111.  
  112.  
  113.     OSErr osErr = NewThread(kCooperativeThread,(ThreadEntryProcPtr)TCooperativeThread::__ThreadMain,this,stackSize,createOptions,&fOutParam,&fThreadID);
  114.     ASSERTNOERR(osErr);
  115.     FailOSErr(osErr);
  116.     
  117.     fWNESleep = wneSleep;
  118.  
  119.     SetThreadSwitcher ( fThreadID, (ThreadSwitchProcPtr) SwitchInProc, (void*) this, true );
  120.     SetThreadSwitcher ( fThreadID, (ThreadSwitchProcPtr) SwitchOutProc, (void*) this, false );
  121.  
  122.     fIdentifierTag = tag;
  123.     
  124.     if( createOptions & kNeedEventQueue ) {
  125.         fEventQueue = new CThreadEventQueue;
  126.     }    
  127.         
  128. }
  129.  
  130.  
  131. //-------------------------------------------------------------------------------------
  132. pascal void* TCooperativeThread::__ThreadMain(void* inParam)
  133. {
  134.     TCooperativeThread* thisThread = (TCooperativeThread*)inParam;
  135.     return thisThread->ThreadMain();        // polymorphic dispatch
  136.     
  137.     //    If you are really paranoid a failure handler should go here.
  138.     //    For now we assume the subclass does this.  Live Dangerously?
  139.     
  140. }
  141.  
  142.  
  143. //-------------------------------------------------------------------------------------
  144. pascal void TCooperativeThread::SwitchInProc ( ThreadID /* threadBeingSwitched */, void* switchProcParam )
  145. {
  146.     TCooperativeThread* thisThread = ( TCooperativeThread *) switchProcParam;
  147.     ASSERT(thisThread);
  148.     
  149.     if ( thisThread ) {
  150.  
  151.         unsigned long savedA5 = ::SetA5( thisThread->fA5 );
  152.         
  153.         gTopHandler = (FailInfoPtr) thisThread->fSavedTopHandler;
  154.         
  155.         gCurrentThread = thisThread;
  156.  
  157.         ::SetA5 ( savedA5 );
  158.  
  159.     }
  160.     
  161. }
  162.  
  163.  
  164.  
  165. //-------------------------------------------------------------------------------------
  166. pascal void TCooperativeThread::SwitchOutProc ( ThreadID /* threadBeingSwitched */, void* switchProcParam )
  167. {
  168.     TCooperativeThread* thisThread = ( TCooperativeThread *) switchProcParam;
  169.     ASSERT(thisThread);
  170.  
  171.     if ( thisThread ) {    
  172.  
  173.         thisThread->fSavedTopHandler = gTopHandler;
  174.     
  175.         gTopHandler = 0;
  176.     
  177.     }
  178. }
  179.  
  180.  
  181. //-------------------------------------------------------------------------------------
  182. void TCooperativeThread::Yield(TCooperativeThread* threadToRun)
  183. {
  184.     OSErr osErr;
  185.     
  186.     if( threadToRun == 0 )
  187.         osErr = YieldToAnyThread();
  188.     else
  189.         osErr = YieldToThread(threadToRun->fThreadID);
  190.  
  191.  
  192.     ASSERTNOERR(osErr);
  193.     
  194. }
  195.  
  196.  
  197.  
  198. //-------------------------------------------------------------------------------------
  199. ThreadState TCooperativeThread::GetThreadState()
  200. {
  201.     ThreadState threadState;
  202.     OSErr osErr = ::GetThreadState(fThreadID,&threadState);
  203.     ASSERTNOERR(osErr);
  204.     
  205.     if( fThreadIOState == sThreadStoppedForIO )
  206.         threadState = (ThreadState) fThreadIOState;        // when stopped for IO return sThreadStoppedForIO
  207.         
  208.     
  209.     return threadState;
  210.     
  211. }
  212.  
  213.  
  214. //-------------------------------------------------------------------------------------
  215. void TCooperativeThread::StopForIO()
  216. {
  217.     fThreadIOState = sThreadStoppedForIO;
  218.     
  219.     OSErr osErr = ::SetThreadState(fThreadID, kStoppedThreadState, kApplicationThreadID);
  220.     ASSERTNOERR(osErr);
  221.     
  222.     fThreadIOState = sThreadIOIdle;
  223.  
  224. }
  225.  
  226.  
  227. //-------------------------------------------------------------------------------------
  228. OSErr TCooperativeThread::QueueEvent(CThreadEvent& threadEvent)
  229. {
  230.     OSErr    osErr = 0;            //•• no errors yet
  231.     
  232.     ASSERT(fEventQueue!=0);
  233.     ASSERT(fEventQueue->EventCount() < kMaxThreadEvents);
  234.     
  235.     if( (fEventQueue != 0) && (fEventQueue->EventCount() < kMaxThreadEvents) ) {
  236.     
  237.         fEventQueue->Insert(threadEvent);
  238.         if( this->IsStopped() ) {
  239.             OSErr    err = this->StartThread();
  240.             gApplication->SetWNESleepTime(this->GetWNESleep()); //••• NEED to work on setting approriate sleep time.
  241.         }
  242.  
  243.     }
  244.     
  245.     return osErr;
  246.     
  247. }
  248.  
  249.  
  250. //-------------------------------------------------------------------------------------
  251. OSErr TCooperativeThread::PostEvent(CThreadEvent& theEvent, Boolean allowDuplicate)
  252. {
  253.     CThreadEventIterator    eventIter(fEventQueue);
  254.     Boolean    queueIt = true;
  255.     
  256.     OSErr osErr = 0;
  257.     
  258.     CThreadEvent* threadEvent;
  259.     for( threadEvent = eventIter.FirstEvent(); eventIter.More(); threadEvent = eventIter.NextEvent() ) {
  260.     
  261.         if( threadEvent->EventID() == theEvent.EventID() ) {
  262.         
  263.             if( !allowDuplicate )
  264.                 queueIt = false;
  265.                 
  266.             break;
  267.         }
  268.         
  269.     }
  270.  
  271.     if( queueIt ) 
  272.         osErr = this->QueueEvent(theEvent);
  273.     return osErr;
  274.     
  275.     
  276. }
  277.  
  278.  
  279. //-------------------------------------------------------------------------------------
  280. OSErr TCooperativeThread::PostEvent(long eventID,long eventData0, Boolean allowDuplicate)
  281. {
  282.     CThreadEvent    threadEvent(eventID,eventData0);
  283.     return this->PostEvent(threadEvent,allowDuplicate);
  284.     
  285. }
  286.  
  287.  
  288. //-------------------------------------------------------------------------------------
  289. CThreadEvent* TCooperativeThread::WaitNextEvent()
  290. {
  291.     OSErr    err;
  292.     
  293.     while( !this->EventAvail() )
  294.     {
  295.         err = this->StopThread();
  296.     }
  297.         
  298.     return this->GetNextEvent();
  299.         
  300. }
  301.  
  302.  
  303.  
  304. //-------------------------------------------------------------------------------------
  305. CThreadEvent* TCooperativeThread::EventAvail()
  306. {
  307.     static CThreadEvent    gNextEvent;
  308.     
  309.     ASSERT(fEventQueue!=0);
  310.     
  311.     if( (fEventQueue != 0) && (fEventQueue->EventCount() != 0) ) {
  312.         fEventQueue->CopyNextEvent(gNextEvent);        // copy it but do not remove it from queue
  313.          return    &gNextEvent;
  314.     }
  315.  
  316.     return 0;
  317.  
  318. }
  319.  
  320.  
  321. //-------------------------------------------------------------------------------------
  322. CThreadEvent* TCooperativeThread::GetNextEvent()
  323. {
  324.     static CThreadEvent    gCurrentEvent;
  325.     
  326.     ASSERT(fEventQueue!=0);
  327.     if( fEventQueue != 0 )
  328.         fEventQueue->Remove(gCurrentEvent);
  329.         
  330.     return    &gCurrentEvent;
  331. }
  332.  
  333.  
  334.  
  335. //---------------------------------------
  336. //        C T h r e a d E v e n t Q u e u e
  337. //----------------------------------------
  338.  
  339. CThreadEventQueue::CThreadEventQueue()
  340. {
  341.     memset(&fEventBufs,0,(kMaxThreadEvents*sizeof(CThreadEvent)));
  342.     
  343.         //    load up the avail able list
  344.         
  345.     for(int i=0;i<kMaxThreadEvents;i++)
  346.         fAvail.LinkTail(&fEventBufs[i]);
  347.         
  348. }
  349.  
  350.  
  351. //-------------------------------------------------------------------------------------
  352. void CThreadEventQueue::Insert(CThreadEvent& threadEvent)
  353. {
  354.     ASSERTPRINT(fEvents.Count() != kMaxThreadEvents,("Overflowed thread eventqueue Event Dropped\n"));
  355.     
  356.     if( fEvents.Count() != kMaxThreadEvents ) {
  357.         
  358.         CThreadEvent* event = (CThreadEvent*) fAvail.UnlinkHead();
  359.         
  360.         BlockMoveData(&threadEvent,event,sizeof(CThreadEvent));
  361.         
  362.         fEvents.LinkTail(event);
  363.         
  364.     }
  365.  
  366. }
  367.  
  368. //-------------------------------------------------------------------------------------
  369. void CThreadEventQueue::Remove(CThreadEvent& threadEvent)
  370. {
  371.     if( fEvents.Count() != 0 ) {
  372.     
  373.         CThreadEvent* event = (CThreadEvent*) fEvents.UnlinkHead();
  374.         BlockMoveData(event,&threadEvent,sizeof(CThreadEvent));
  375.         fAvail.LinkTail(event);
  376.                 
  377.     } else {
  378.         memset(&threadEvent,0,sizeof(CThreadEvent)) ;        // make it null event
  379.     
  380.     }
  381.     
  382.     
  383. }
  384.  
  385. //-------------------------------------------------------------------------------------
  386. void CThreadEventQueue::FlushEvents(long eventID)
  387. {
  388.  
  389.     CLinkedListIterator    iter(&fEvents);
  390.     CThreadEvent* threadEvent;
  391.     for(threadEvent = (CThreadEvent*)iter.FirstItem(); iter.More(); threadEvent = (CThreadEvent*)iter.NextItem() ) {
  392.     
  393.         if( eventID == 'all ' || threadEvent->EventID() == eventID ) {
  394.         
  395.             iter.UnlinkCurrentItem();
  396.             fAvail.LinkTail(threadEvent);
  397.             
  398.         }
  399.         
  400.         
  401.     }
  402.     
  403. }
  404.  
  405.  
  406.  
  407. //-------------------------------------------------------------------------------------
  408. void CThreadEventQueue::CopyNextEvent(CThreadEvent& threadEvent) 
  409. {
  410.     CThreadEvent* event = (CThreadEvent*) fEvents.Head();
  411.     
  412.     if( event != 0 )
  413.         BlockMoveData(event,&threadEvent,sizeof(CThreadEvent));
  414.         
  415. }
  416.  
  417. //-----------------------------------------------
  418. //        T A p p l i c a t i o n T h r e a d
  419. //-----------------------------------------------
  420.  
  421.  
  422. //-------------------------------------------------------------------------------------
  423. void* TApplicationThread::ThreadMain()
  424. {
  425.     ASSERTPRINT(false,("What the hell ya doin here?\n"));
  426.     
  427.     return 0;
  428. }
  429.  
  430. //-------------------------------------------------------------------------------------
  431. void TApplicationThread::IApplicationThread()
  432. {
  433.  
  434.     //    A little be sleazy.  We don't call ICooperativeThread cause
  435.     //    the application thread is automagically created by the thread
  436.     //    manager.  But we do need to switch it in and out.
  437.     
  438.     fIdentifierTag = 'main';
  439.  
  440.     fWNESleep = kSleepTime;
  441.     fThreadID = kApplicationThreadID;
  442.     fSavedTopHandler = gTopHandler;
  443.  
  444.  
  445.     SetThreadSwitcher ( fThreadID, (ThreadSwitchProcPtr) SwitchInProc, (void*) this, true );
  446.     SetThreadSwitcher ( fThreadID, (ThreadSwitchProcPtr) SwitchOutProc, (void*) this, false );
  447.     
  448.     FailOSErr( GetThreadCurrentTaskRef(&gAppTaskRef) );
  449. }
  450.  
  451.  
  452.  
  453. //-----------------------------
  454. //    T W a k e u p T h r e a d 
  455. //----------------------------
  456.  
  457. //---------------------------------------------------------------
  458. TWakeupThread::TWakeupThread()
  459. {
  460.     fThreadToWake = 0;
  461. }
  462.  
  463. //---------------------------------------------------------------
  464. void* TWakeupThread::ThreadMain()
  465. {
  466.     while(true) {
  467.     
  468.         ASSERT(fThreadToWake!=0);
  469.         OSErr    err = fThreadToWake->StartThread();
  470.         
  471.         gDebugCallCount++;
  472.         
  473.         err = this->StopThread();
  474.         
  475.     }
  476.     
  477.     return this;
  478. }
  479.  
  480. //---------------------------------------------------------------
  481. void TWakeupThread::IWakeupThread()
  482. {
  483.         //    These threads need very little stack.
  484.         
  485.     this->ICooperativeThread('wake', kWakeupThreadStacksize,kNewSuspend);
  486.     
  487. }
  488.  
  489.